/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package hextd.message;

import hextd.message.MessageFactory.NetworkMessage;
import hextd.core.MapInfo;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MessageMapListOld implements Message {

	public NetworkMessage type = NetworkMessage.MapListOld;
	public static char separator = ';';
	public static char separator2 = ',';
	// MAPLIST ;map1;map2; CAT ;cat1;cat2;
	// map = mapId,title,changedTime,players,catId
	// cat = catId,title
	public static String RegExp = "MAPLIST (" +
			separator +
			"([^" + separator + " ]+" +
			separator + ")+)" +
			"($| CAT (" +
			separator +
			"([^" + separator + " ]+" +
			separator + ")+)$)";
	public static Pattern MessagePattern = Pattern.compile(MessageMapListOld.RegExp);
	//
	private String message;
	private Map<Integer, MapInfo> mapCache;
	private ArrayList<MapInfo> mapList;
	private Map<Integer, String> categories;

	public static String formatMessage(Set<MapInfo> maps, Map<Integer, String> categories) {
		String message = "MAPLIST " + separator + "";
		for (MapInfo m : maps) {
			try {
				message += "" + m.mapId +
						separator2 + URLEncoder.encode(m.title, "UTF-8") +
						separator2 + m.lastChange +
						separator2 + m.players +
						separator2 + m.category +
						separator + "";
			} catch (UnsupportedEncodingException ex) {
				Logger.getLogger(MessageMapListOld.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
		if (!categories.isEmpty()) {
			message += " CAT " + separator;
			for (Entry<Integer, String> entry : categories.entrySet()) {
				try {
					message += URLEncoder.encode(entry.getKey().toString(), "UTF-8") +
							separator2 +
							URLEncoder.encode(entry.getValue().toString(), "UTF-8") +
							separator;
				} catch (UnsupportedEncodingException ex) {
					Logger.getLogger(MessageMapListOld.class.getName()).log(Level.SEVERE, null, ex);
				}
			}
		}
		return message;
	}

	public MessageMapListOld() {
	}

	private MessageMapListOld(String message) {
		this.message = message;
		Matcher matcher = MessageMapListOld.MessagePattern.matcher(message);
		if (matcher.matches()) {
			// First handle the categories (if any)
			String catsString = matcher.group(4);
			if (catsString != null) {
				catsString = catsString.substring(1, catsString.length() - 1);
				String[] catsArray = catsString.split("" + separator);
				categories = new HashMap<Integer, String>();
				for (String catString : catsArray) {
					String[] catArray = catString.split("" + separator2);
					try {
						Integer key = new Integer(catArray[0]);
						String name = URLDecoder.decode(catArray[1], "UTF-8");
						categories.put(key, name);
					} catch (NumberFormatException e) {
						System.err.println("MML: not an int decoding " + catArray[0]);
					} catch (UnsupportedEncodingException e) {
						Logger.getLogger(MessageMapListOld.class.getName()).log(Level.SEVERE, null, e);
					}
				}

			}
			// Now handle the maps
			mapCache = new HashMap<Integer, MapInfo>();
			String mapString = matcher.group(1);
			mapString = mapString.substring(1, mapString.length() - 1);
			String[] mapsArray = mapString.split("" + separator);
			mapList = new ArrayList<MapInfo>(mapsArray.length);
			for (int i = 0; i < mapsArray.length; i++) {
				String[] mapArray = mapsArray[i].split("" + separator2);
				try {
					MapInfo info = new MapInfo();
					info.mapId = Integer.parseInt(mapArray[0]);
					info.title = URLDecoder.decode(mapArray[1], "UTF-8");
					info.lastChange = Integer.parseInt(mapArray[2]);
					info.players = Integer.parseInt(mapArray[3]);
					if (mapArray.length > 4) {
						info.category = Integer.parseInt(mapArray[4]);
					}
					mapCache.put(info.mapId, info);
					mapList.add(info);
				} catch (NumberFormatException e) {
					System.err.println("MessageChannelList: invalid number in: " + mapsArray[i] + " from: " + message);
				} catch (UnsupportedEncodingException ex) {
					Logger.getLogger(MessageMapListOld.class.getName()).log(Level.SEVERE, null, ex);
				}
			}
		}
	}

	public Map<Integer, MapInfo> getMapCache() {
		return mapCache;
	}

	public Map<Integer, String> getCategories() {
		return categories;
	}

	public List<MapInfo> getMapList() {
		return mapList;
	}

	@Override
	public String getMessage() {
		return this.message;
	}

	@Override
	public Message initFromString(String message) {
		MessageMapListOld messageMapListOld = new MessageMapListOld(message);
		Map<Integer, String> cats = messageMapListOld.getCategories();
		if (cats == null) {
			cats = new HashMap<Integer, String>();
		}
		String messageMapListNewString = MessageMapList.formatMessage(messageMapListOld.getMapList(), cats);
		Message messageMapListNew = (new MessageMapList()).initFromString(messageMapListNewString);
		return messageMapListNew;
	}

	@Override
	public int getSenderId() {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public void setSenderId(int id) {
		throw new UnsupportedOperationException("Not supported yet.");
	}

	@Override
	public Pattern getPattern() {
		return MessageMapListOld.MessagePattern;
	}

	@Override
	public NetworkMessage getType() {
		return this.type;
	}
}
